#!/usr/bin/python3
# -*- coding: utf-8 -*-
# pylint: disable=C0103

""" 

常量定义。

"""

from ctypes.wintypes import LONG, HWND, UINT
# from ctypes.wintypes import DWORD, LONG, HWND, UINT, ULONG, BOOL, LPLONG, LPCSTR
from ctypes import c_int

def Constant(cls=None):
    """ 装饰器， 把函数转为常量。 """
    def decorator(func):
        variable = func()
        if cls is None or isinstance(variable, cls):
            return variable
        else:
            return cls(variable)
    return decorator

@Constant(cls=HWND)
def HWND_BOTTOM() -> HWND:
    """ 将窗口置于 Z 顺序的底部。 如果 hWnd 参数标识最顶层的窗口，该窗口将失去其最顶层的状态，并放置在所有其他窗口的底部。 """
    return HWND(1)

@Constant(cls=HWND)
def HWND_NOTOPMOST() ->HWND:
    """ 将窗口置于所有非最顶部窗口 (即) 所有最顶部窗口的后面。 如果窗口已经是非最顶部窗口，则此标志不起作用。 """
    return HWND(-2)

@Constant(cls=HWND)
def HWND_TOP() ->HWND:
    """ 将窗口置于 Z 顺序的顶部。 """
    return HWND(0)

@Constant(cls=HWND)
def HWND_TOPMOST() ->HWND:
    """ 将窗口置于所有非最顶部窗口的上面。 该窗口即使已停用，也会保留在最高位置。 """
    return HWND(-1)

class GetWindowLongIndex(c_int):
    " 用于GetWindowLong 第二个参数的整数值。 "
    def __repr__(self):
        return f"GetWindowLongIndex({hex(UINT(self.value).value)})"

@Constant(cls=GetWindowLongIndex)
def GWL_EXSTYLE():
    " 设置新的 扩展窗口样式。"
    return -20

@Constant(cls=GetWindowLongIndex)
def GWL_HINSTANCE():
    " 设置新的应用程序实例句柄。"
    return -6

@Constant(cls=GetWindowLongIndex)
def GWL_ID():
    " 设置子窗口的新标识符。 该窗口不能是顶级窗口。"
    return -12

@Constant(cls=GetWindowLongIndex)
def GWL_STYLE():
    " 设置新 窗口样式。"
    return -16

@Constant(cls=GetWindowLongIndex)
def GWL_USERDATA():
    " 设置与窗口关联的用户数据。 其值最初为零。"
    return -21

@Constant(cls=GetWindowLongIndex)
def GWL_WNDPROC():
    " 为窗口过程设置新地址。 如果窗口不属于所在的进程，则无法更改此属性。"
    return -4

class WindowStyle(LONG):
    " WindowStyle 窗口风格整数 "
    def __repr__(self):
        lines = [
            f"WindowStyle ({hex(self.value)})",
            f"WS_BORDER({hex(WS_BORDER.value)}) = {hex(WS_BORDER.value & self.value)}",
            f"WS_CAPTION({hex(WS_CAPTION.value)}) = {hex(WS_CAPTION.value & self.value)}",
            f"WS_CHILD({hex(WS_CHILD.value)}) = {hex(WS_CHILD.value & self.value)}",
            f"WS_CLIPCHILDREN({hex(WS_CLIPCHILDREN.value)}) = {hex(WS_CLIPCHILDREN.value & self.value)}"
            ]
        return '\n'.join(lines)

@Constant(cls=WindowStyle)
def WS_BORDER():
    """ 窗口具有细线边框。 """
    return 0x00800000

@Constant(cls=WindowStyle)
def WS_CAPTION():
    """ 窗口具有标题栏， (包含 WS_BORDER 样式) 。 """
    return 0x00C00000

@Constant(cls=WindowStyle)
def WS_CHILD():
	""" 窗口是子窗口。 具有此样式的窗口不能有菜单栏。 此样式不能与 WS_POPUP 样式一起使用。 """
	return 0x40000000

@Constant(cls=WindowStyle)
def WS_CHILDWINDOW():
	""" 与 WS_CHILD 样式相同。 """
	return 0x40000000

@Constant(cls=WindowStyle)
def WS_CLIPCHILDREN():
	""" 排除在父窗口内进行绘制时子窗口占用的区域。 创建父窗口时使用此样式。 """
	return 0x02000000

@Constant(cls=WindowStyle)
def WS_CLIPSIBLINGS():
	""" 相对于彼此剪裁子窗口;也就是说，当特定子窗口收到 WM_PAINT 消息时， WS_CLIPSIBLINGS 样式会将所有其他重叠的子窗口剪裁到子窗口的区域之外进行更新。 如果未指定 WS_CLIPSIBLINGS 且子窗口重叠，则当在子窗口的工作区内绘图时，可以在相邻子窗口的工作区内绘制。 """
	return 0x04000000

@Constant(cls=WindowStyle)
def WS_DISABLED():
	""" 窗口最初处于禁用状态。 已禁用的窗口无法接收用户的输入。 若要在创建窗口后更改此设置，请使用 EnableWindow 函数。 """
	return 0x08000000

@Constant(cls=WindowStyle)
def WS_DLGFRAME():
	""" 窗口具有通常与对话框一起使用的样式的边框。 具有此样式的窗口不能具有标题栏。 """
	return 0x00400000

@Constant(cls=WindowStyle)
def WS_GROUP():
	""" 窗口是一组控件的第一个控件。 组由第一个控件及其后定义的所有控件组成，以及具有 WS_GROUP 样式的下一个控件。 每个组中的第一个控件通常具有 WS_TABSTOP 样式，以便用户可以在组之间移动。 用户随后可以使用方向键将键盘焦点从组中的一个控件更改为组中的下一个控件。 """
	return 0x00020000

@Constant(cls=WindowStyle)
# 可以打开和关闭此样式以更改对话框导航。 若要在创建窗口后更改此样式，请使用 SetWindowLong 函数。
def WS_HSCROLL():
	""" 窗口具有水平滚动条。 """
	return 0x00100000

@Constant(cls=WindowStyle)
def WS_ICONIC():
	""" 窗口最初最小化。 与 WS_MINIMIZE 样式相同。 """
	return 0x20000000

@Constant(cls=WindowStyle)
def WS_MAXIMIZE():
    """ 窗口最初是最大化的。 """
    return 0x01000000

@Constant(cls=WindowStyle)
def WS_MAXIMIZEBOX():
    """ 窗口有一个“最大化”按钮。 不能与 WS_EX_CONTEXTHELP 样式组合使用。 还必须指定 WS_SYSMENU 样式。 """
    return 0x00010000

@Constant(cls=WindowStyle)
def WS_MINIMIZE():
    """ 窗口最初最小化。 与 WS_ICONIC 样式相同。 """
    return 0x20000000

@Constant(cls=WindowStyle)
def WS_MINIMIZEBOX():
    """ 窗口有一个最小化按钮。 不能与 WS_EX_CONTEXTHELP 样式组合使用。 还必须指定 WS_SYSMENU 样式。 """
    return 0x00020000

@Constant(cls=WindowStyle)
def WS_OVERLAPPED():
    """ 窗口是重叠的窗口。 重叠的窗口带有标题栏和边框。 与 WS_TILED 样式相同。 """
    return 0x00000000

@Constant(cls=WindowStyle)
def WS_POPUP():
    """ 窗口是弹出窗口。 此样式不能与 WS_CHILD 样式一起使用。 """
    return 0x80000000

@Constant(cls=WindowStyle)
def WS_SIZEBOX():
    """ 窗口具有大小调整边框。 与 WS_THICKFRAME 样式相同。 """
    return 0x00040000

@Constant(cls=WindowStyle)
def WS_SYSMENU():
    """ 窗口的标题栏上有一个窗口菜单。 还必须指定 WS_CAPTION 样式。 """
    return 0x00080000

@Constant(cls=WindowStyle)
def WS_TABSTOP():
    """ 窗口是一个控件，当用户按下 TAB 键时，该控件可以接收键盘焦点。 
    按 Tab 键将键盘焦点更改为具有 WS_TABSTOP 样式的下一个控件。 
    可以打开和关闭此样式以更改对话框导航。 
    若要在创建窗口后更改此样式，请使用 SetWindowLong 函数。 
    若要使用户创建的窗口和无模式对话框使用制表位，请更改消息循环以调用 IsDialogMessage 函数。
    """
    return 0x00010000

@Constant(cls=WindowStyle)
def WS_THICKFRAME():
    """ 窗口具有调整大小边框。 与 WS_SIZEBOX 样式相同。 """
    return 0x00040000

@Constant(cls=WindowStyle)
def WS_TILED():
    """ 该窗口是一个重叠的窗口。 重叠的窗口带有标题栏和边框。 与 WS_OVERLAPPED 样式相同。 """
    return 0x00000000

@Constant(cls=WindowStyle)
def WS_VISIBLE():
    """ 该窗口最初是可见的。 可以使用 ShowWindow 或 SetWindowPos 函数打开和关闭此样式。 """
    return 0x10000000

@Constant(cls=WindowStyle)
def WS_VSCROLL():
    """ 窗口具有垂直滚动条。 """
    return 0x00200000

@Constant(cls=WindowStyle)
def WS_OVERLAPPEDWINDOW():
    """	窗口是重叠的窗口。
    与 WS_TILEDWINDOW 样式相同。 

    """
    return ( WS_OVERLAPPED.value | WS_CAPTION.value | WS_SYSMENU.value
            | WS_THICKFRAME.value | WS_MINIMIZEBOX.value | WS_MAXIMIZEBOX.value )

@Constant(cls=WindowStyle)
def WS_POPUPWINDOW():
    """	窗口是弹出窗口。
    必须组合 WS_CAPTION 和 WS_POPUPWINDOW 样式，使窗口菜单可见。

    """
    return WS_POPUP.value | WS_BORDER.value | WS_SYSMENU.value

@Constant(cls=WindowStyle)
def WS_TILEDWINDOW():
    """ 该窗口是一个重叠的窗口。
    与 WS_OVERLAPPEDWINDOW 样式相同。
    """
    return ( WS_OVERLAPPED.value | WS_CAPTION.value | WS_SYSMENU.value |
            WS_THICKFRAME.value | WS_MINIMIZEBOX.value | WS_MAXIMIZEBOX.value )

class WindowStyleEx(WindowStyle):
    """ 扩展窗口样式
    """
    def __repr__(self):
        return f"WindowStyleEx({hex(ULONG(self.value).value)})"

@Constant(cls=WindowStyleEx)
def WS_EX_ACCEPTFILES():
    """ 窗口接受拖放文件。
    """
    return  0x00000010

@Constant(cls=WindowStyleEx)
def WS_EX_APPWINDOW():
    """ 在顶级窗口可见时强行将其放在任务栏上。 """
    return 0x00040000

@Constant(cls=WindowStyleEx)
def WS_EX_CLIENTEDGE():
    """ 窗口有一个带有凹陷边缘的边框。 """
    return 0x00000200

@Constant(cls=WindowStyleEx)
def WS_EX_COMPOSITED():
    """ 使用双缓冲按从下到上绘制顺序绘制窗口的所有后代。 从下到上绘制顺序允许后代窗口具有半透明 (alpha) 和透明度 (颜色键) 效果，但前提是后代窗口还设置了WS_EX_TRANSPARENT位。 通过双重缓冲，可以在不闪烁的情况下绘制窗口及其后代。 如果窗口的 类样式 为 CS_OWNDC 或 CS_CLASSDC，则无法使用此选项。 Windows 2000： 不支持此样式。 """
    return 0x02000000

@Constant(cls=WindowStyleEx)
def WS_EX_CONTEXTHELP():
    """ 窗口的标题栏包含问号。 当用户单击该问号时，光标将变成带指针的问号。 如果用户随后单击子窗口，则子窗口将收到 WM_HELP 消息。 子窗口应将消息传递到父窗口过程，父窗口过程应使用 HELP_WM_HELP 命令调用 WinHelp 函数。 帮助应用程序显示一个弹出窗口，该窗口通常包含子窗口的帮助。 WS_EX_CONTEXTHELP 不能与 WS_MAXIMIZEBOX 或 WS_MINIMIZEBOX 样式一起使用。 """
    return 0x00000400

@Constant(cls=WindowStyleEx)
def WS_EX_CONTROLPARENT():
    """ 窗口本身包含应参与对话框导航的子窗口。
    如果指定了此样式，则执行导航操作（例如处理 TAB 键、箭头键或键盘助记键）时，对话管理器将递归为此窗口的子级。
    """
    return 0x00010000

@Constant(cls=WindowStyleEx)
def WS_EX_DLGMODALFRAME():
    """ 窗口有一个双边框：（可选）可以通过在 dwStyle 参数中指定WS_CAPTION样式来创建带有标题栏的窗口。 """
    return 0x00000001

@Constant(cls=WindowStyleEx)
def WS_EX_LAYERED():
    """ 该窗口是一个分层窗口。
    如果窗口的 类样式 为 CS_OWNDC 或 CS_CLASSDC，则不能使用此样式。
    Windows 8：顶级窗口和子窗口支持WS_EX_LAYERED样式。
    以前的 Windows 版本仅支持 顶级窗口WS_EX_LAYERED 。
    """
    return 0x00080000

@Constant(cls=WindowStyleEx)
def WS_EX_LAYOUTRTL():
    """ 如果 shell 语言是希伯来语、阿拉伯语或其他支持阅读顺序对齐的语言，则窗口的水平原点位于右边缘。
    增加水平值后向左。
    """
    return 0x00400000

@Constant(cls=WindowStyleEx)
def WS_EX_LEFT():
    """ 窗口具有泛型左对齐属性。
    这是默认设置。
    """
    return 0x00000000

@Constant(cls=WindowStyleEx)
def WS_EX_LEFTSCROLLBAR():
    """ 如果 shell 语言是希伯来语、阿拉伯语或其他支持阅读顺序对齐的语言，则垂直滚动条 (（如果存在) ）位于工作区左侧。
    对于其他语言，将忽略该样式。
    """
    return 0x00004000

@Constant(cls=WindowStyleEx)
def WS_EX_LTRREADING():
    """ 窗口文本使用从左到右的阅读顺序属性显示。 这是默认值。 """
    return 0x00000000

@Constant(cls=WindowStyleEx)
def WS_EX_MDICHILD():
    """ 该窗口是 MDI 子窗口。 """
    return 0x00000040

@Constant(cls=WindowStyleEx)
def WS_EX_NOACTIVATE():
    """ 用户单击时，使用此样式创建的顶级窗口不会成为前台窗口。
    当用户最小化或关闭前台窗口时，系统不会将此窗口带到前台。
    不应通过编程访问或通过键盘导航（如讲述人）激活窗口。
    若要激活窗口，请使用 SetActiveWindow 或 SetForegroundWindow 函数。
    默认情况下，窗口不会显示在任务栏上。
    若要强制窗口显示在任务栏上，请使用 WS_EX_APPWINDOW 样式。
    """
    return 0x08000000

@Constant(cls=WindowStyleEx)
def WS_EX_NOINHERITLAYOUT():
    """ 窗口不将其窗口布局传递给其子窗口。 """
    return 0x00100000

@Constant(cls=WindowStyleEx)
def WS_EX_NOPARENTNOTIFY():
    """ 使用此样式创建的子窗口在创建或销毁时不会将 WM_PARENTNOTIFY 消息发送到其父窗口。 """
    return 0x00000004

@Constant(cls=WindowStyleEx)
def WS_EX_NOREDIRECTIONBITMAP():
    """ 窗口不会呈现到重定向图面。 这适用于没有可见内容或使用表面以外的机制提供其视觉对象的窗口。 """
    return 0x00200000

@Constant(cls=WindowStyleEx)
def WS_EX_RIGHT():
    """ 窗口具有通用的“右对齐”属性。
    这依赖于窗口类。
    仅当 shell 语言是希伯来语、阿拉伯语或其他支持阅读顺序对齐的语言时，此样式才有效;否则，将忽略该样式。
    对静态控件或编辑控件使用 WS_EX_RIGHT 样式的效果与分别使用 SS_RIGHT 或 ES_RIGHT 样式的效果相同。
    将此样式用于按钮控件的效果与使用 BS_RIGHT 和 BS_RIGHTBUTTON 样式的效果相同。
    """
    return 0x00001000

@Constant(cls=WindowStyleEx)
def WS_EX_RIGHTSCROLLBAR():
    """ 如果) 位于工作区右侧，则垂直滚动条 (。 这是默认值。 """
    return 0x00000000

@Constant(cls=WindowStyleEx)
def WS_EX_RTLREADING():
    """ 如果 shell 语言是希伯来语、阿拉伯语或其他支持阅读顺序对齐的语言，则使用从右到左的阅读顺序属性显示窗口文本。
    对于其他语言，将忽略该样式。
    """
    return 0x00002000

@Constant(cls=WindowStyleEx)
def WS_EX_STATICEDGE():
    """ 窗口具有三维边框样式，旨在用于不接受用户输入的项。 """
    return 0x00020000

@Constant(cls=WindowStyleEx)
def WS_EX_TOOLWINDOW():
    """ 该窗口旨在用作浮动工具栏。 工具窗口具有短于普通标题栏的标题栏和使用较小的字体绘制的窗口标题。 工具窗口不会显示在任务栏中，也不会显示在用户按 Alt+TAB 时显示的对话框中。 如果工具窗口具有系统菜单，则其图标不会显示在标题栏上。 但是，可以通过右键单击或键入 ALT+SPACE 来显示系统菜单。 """
    return 0x00000080

@Constant(cls=WindowStyleEx)
def WS_EX_TOPMOST():
    """ 窗口应放置在所有非最顶部窗口的上方，并且应保持在窗口上方，即使窗口已停用也是如此。 若要添加或删除此样式，请使用 SetWindowPos 函数。 """
    return 0x00000008

@Constant(cls=WindowStyleEx)
def WS_EX_TRANSPARENT():
    """ 在绘制由同一线程 创建的窗口下的同级 之前，不应绘制窗口。
    该窗口显示为透明，因为基础同级窗口的位已被绘制。
    若要在不受这些限制的情况下实现透明度，请使用 SetWindowRgn 函数。
    """
    return 0x00000020

@Constant(cls=WindowStyleEx)
def WS_EX_WINDOWEDGE():
    """ 窗口的边框带有凸起的边缘。 """
    return 0x00000100

@Constant(cls=WindowStyleEx)
def WS_EX_OVERLAPPEDWINDOW():
    """  窗口是重叠的窗口。 """
    return WS_EX_WINDOWEDGE.value | WS_EX_CLIENTEDGE.value

@Constant(cls=WindowStyleEx)
def WS_EX_PALETTEWINDOW():
    """ 窗口是调色板窗口，它是一个无模式对话框，显示命令数组。
    """
    return WS_EX_WINDOWEDGE.value |WS_EX_TOOLWINDOW.value |WS_EX_TOPMOST.value


WM_SYSCOMMAND = UINT(0x0112)

class SystemCommand(UINT):
    """
    """
    def __repr__(self):
        return f"SystemCommand({hex(self.value)})"


@Constant(cls=SystemCommand)
def SC_CLOSE() -> UINT:
    """ 关闭窗口。 """
    return 0xF060


@Constant(cls=SystemCommand)
def SC_CONTEXTHELP() -> UINT:
    """ 使用指针将光标更改为问号。 如果用户随后单击对话框中的控件，该控件将收到 WM_HELP 消息。 """
    return 0xF180


@Constant(cls=SystemCommand)
def SC_DEFAULT() -> UINT:
    """ 选择默认项;用户双击窗口菜单。 """
    return 0xF160


@Constant(cls=SystemCommand)
def SC_HOTKEY() -> UINT:
    """ 激活与应用程序指定的热键关联的窗口。 lParam 参数标识要激活的窗口。 """
    return 0xF150


@Constant(cls=SystemCommand)
def SC_HSCROLL() -> UINT:
    """ 水平滚动。 """
    return 0xF080


SCF_ISSECURE = UINT(0x00000001)     # 指示屏幕保护程序是否安全。
@Constant(cls=SystemCommand)
def SC_KEYMENU() -> UINT:
    """ 检索作为击键结果的窗口菜单。 有关详细信息，请参见“备注”部分。 """
    return 0xF100


@Constant(cls=SystemCommand)
def SC_MAXIMIZE() -> UINT:
    """ 最大化窗口。 """
    return 0xF030


@Constant(cls=SystemCommand)
def SC_MINIMIZE() -> UINT:
    """ 最小化窗口。 """
    return 0xF020


@Constant(cls=SystemCommand)
def SC_MONITORPOWER() -> UINT:
    """ 设置显示的状态。 此命令支持具有节能功能的设备，例如电池供电的个人计算机。 """
    return 0xF170


# lParam 参数可以具有以下值：
# -1 (显示器打开)
# 1 (显示器将进入低功耗)
# 2 (显示器正在关闭)
@Constant(cls=SystemCommand)
def SC_MOUSEMENU() -> UINT:
    """ 检索鼠标单击后窗口菜单。 """
    return 0xF090


@Constant(cls=SystemCommand)
def SC_MOVE() -> UINT:
    """ 移动窗口。 """
    return 0xF010


@Constant(cls=SystemCommand)
def SC_NEXTWINDOW() -> UINT:
    """ 移动到下一个窗口。 """
    return 0xF040


@Constant(cls=SystemCommand)
def SC_PREVWINDOW() -> UINT:
    """ 移动到上一个窗口。 """
    return 0xF050


@Constant(cls=SystemCommand)
def SC_RESTORE() -> UINT:
    """ 将窗口还原到其正常位置和大小。 """
    return 0xF120


@Constant(cls=SystemCommand)
def SC_SCREENSAVE() -> UINT:
    """ 执行在 System.ini 文件的 [boot] 节中指定的屏幕保护程序应用程序。 """
    return 0xF140


@Constant(cls=SystemCommand)
def SC_SIZE() -> UINT:
    """ 调整窗口大小。 """
    return 0xF000


@Constant(cls=SystemCommand)
def SC_TASKLIST() -> UINT:
    """ 激活“ 开始 ”菜单。 """
    return 0xF130


@Constant(cls=SystemCommand)
def SC_VSCROLL() -> UINT:
    """ 垂直滚动。 """
    return 0xF070
